#include "head.h"

void sigHandler(int argc){
    write(pfd[1], "ok", 2);
    return;
}


int main(int argc, char **argv){
    
    pipe(pfd);
    
    if(fork() == 0){
        
        close(pfd[1]);

        ARGS_CHECK(argc, 4);

        // 1.创建监听socket
        int sockfd = establishConnect(argv[1], argv[2]);


        // 2.创建线程池
        threadPool_t threadPool;
        int threadCount = atoi(argv[3]);
        makeWorker(&threadPool, threadCount);

        int efd = epoll_create(1);
        if(efd == -1){
            printf("efd error");
            return -1;
        }
        threadPool.efd = efd;


        pthread_mutex_lock(&threadPool.mutex);
        MYSQL *mysql = mysql_init(NULL);
        MYSQL *ret = mysql_real_connect(mysql, "localhost", "root", "123", "netdisk_v3", 3306, NULL, 0); 
        pthread_mutex_unlock(&threadPool.mutex);

        if(ret == NULL){
            fprintf(stderr, "mysql error: %s\n", mysql_error(mysql));
            exit(EXIT_FAILURE);
        }


        // 3.将监听socket加入监听队列
        epollAdd(efd, sockfd);
        epollAdd(efd, pfd[0]);
        // 4.加入超时数组
        timeOutTool_t *timeOutArr = (timeOutTool_t *)calloc(TIMEOUT, sizeof(timeOutTool_t));
        threadPool.timeOutArr = timeOutArr; 

        struct epoll_event readySet[1024];
        time_t curTime = time(NULL);
        while(1){
            // 每过一秒去看有谁超时
            int readyCount = epoll_wait(efd, readySet, 1023, 1000);
            if(time(NULL) - curTime > 0){
                curTime = time(NULL);
                // 踢人
                int index = (curTime + 1) % TIMEOUT;
                while(timeOutArr[index].len != 0){
                    fdNode_t *curNode = timeOutArr[index].head;

                    printf("curTime : %s\n", ctime(&curTime));
                    
                    // 关闭连接，去除监听
                    printf("close fd: %d\n", curNode->netfd);
                    epollDel(efd, curNode->netfd);
                    close(curNode->netfd);
                    threadPool.recordUserId[curNode->netfd] = 0;
                    // 从超时数组剔除
                    delNodeInTimeOutTool(&timeOutArr[index], curNode);
                    printf("curNode %d\n", curNode->netfd);
                    free(curNode);
                }
            }

            // 有东西就绪
            for(int i = 0; i < readyCount; i++){

                // 1.是连接
                if(readySet[i].data.fd == sockfd){
                    
                    printf("have connect\n");

                    int connectfd = accept(sockfd, NULL, NULL);
                    train_t mess;
                    mess.type = LOGIN_USERNAME;

                    pthread_mutex_lock(&threadPool.mutex);

                    enQueue(&threadPool.workQueue, connectfd, mess);

                    pthread_cond_broadcast(&threadPool.cond);
                    pthread_mutex_unlock(&threadPool.mutex);
                }else if(readySet[i].data.fd == pfd[0]){
                    // 优雅退出
                    // 加锁改存在标志位
                    pthread_mutex_lock(&threadPool.mutex);
                    
                    threadPool.existStatus = 0;
                    pthread_cond_broadcast(&threadPool.cond);
                    pthread_mutex_unlock(&threadPool.mutex);
                    
                    /* printf("exit\n"); */

                    for(int i = 0; i < threadPool.tidArr.count; i++){
                        printf("thread id = %lu exit\n", threadPool.tidArr.arr[i].threadId);
                        pthread_join(threadPool.tidArr.arr[i].threadId, NULL);
                    }
                    return 0;
                }
                // 2.是客户发消息
                else{
                    train_t mess;
                    fdNode_t *curReadyNode = (fdNode_t *)readySet[i].data.ptr;
                    // 更新超时表
                    int index = time(NULL) % TIMEOUT;
                    delNodeInTimeOutTool(&timeOutArr[curReadyNode->curIndex], curReadyNode);
                    curReadyNode->curIndex = index;
                    // 添加到目前的表中
                    addNodeInTimeOutTool(&timeOutArr[index], curReadyNode);

                    int curfd = curReadyNode->netfd;

                    printf("have mess\n");

                    int ret = recvRequest(curfd, &mess);
                    if(ret < 0){
                        printf("other disconect\n");
                        threadPool.recordUserId[curfd] = 0;
                        epollDel(efd, curfd);
                        continue;
                    }
                    // 指令分发
                    printf("type : %d\n", mess.type);
                    printf("mess:--%s--\n", mess.buf);
                    switch(mess.type){
                    case PUTS:
                    case GETS:
                        pthread_mutex_lock(&threadPool.mutex);

                        enQueue(&threadPool.workQueue, curfd, mess);

                        pthread_cond_broadcast(&threadPool.cond);
                        pthread_mutex_unlock(&threadPool.mutex);
                        epollDel(efd, curfd);
                        break;
                    case CD: cdOrder(mysql, threadPool.recordUserId[curfd], curfd, mess.buf); break;
                    case LS: lsOrder(mysql, threadPool.recordUserId[curfd], curfd, mess.buf); break;
                    case MKDIR: mkdirOrder(mysql, threadPool.recordUserId[curfd], curfd, mess.buf); break;
                    case RMDIR: rmdirOrder(mysql, threadPool.recordUserId[curfd], curfd, mess.buf); break;
                    case RMDIR_R: rmdir_rOrder(mysql, threadPool.recordUserId[curfd], curfd, mess.buf); break;
                    case PWD: pwdOrder(mysql, threadPool.recordUserId[curfd], curfd); break;
                    case REMOVE: removeOrder(mysql, threadPool.recordUserId[curfd], curfd, mess.buf); break;
                    default: RETERROR2("Invalid order."); break;
                    }
                }
            }
        }
    }else{
        // 注册信号
        close(pfd[0]);
        signal(SIGUSR1, sigHandler);
    }


    // 主进程
    wait(NULL);
}
